package com.guguguweb.rpc.net.server.Handler;


import com.guguguweb.rpc.entity.RpcRequest;
import com.guguguweb.rpc.provider.LocalServiceProviderImpl;
import com.guguguweb.rpc.provider.ServiceProvider;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.DefaultEventExecutor;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NettyServerHandler extends SimpleChannelInboundHandler<RpcRequest> {

    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);

    private  LocalRequestHandler requestHandler;


    private static final EventExecutorGroup group = new DefaultEventExecutorGroup(2*Runtime.getRuntime().availableProcessors());

    public static NettyServerHandler build(){
        return new NettyServerHandler(new LocalRequestHandler(new LocalServiceProviderImpl()));
    }

    public NettyServerHandler(LocalRequestHandler requestHandler){
        this.requestHandler = requestHandler;
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
            IdleState state = ((IdleStateEvent) evt).state();
            if(state == IdleState.READER_IDLE){
                logger.info("长时间未收到心跳包，断开连接……");
                ctx.close();
            }
        }else {
            super.userEventTriggered(ctx, evt);
        }
    }


    @Override
    public void channelRead0(ChannelHandlerContext ctx, RpcRequest msg) throws Exception {
        try{
            if(msg.getHeartBeat()){
                logger.debug("接收到客户端心跳包……");
                return;
            }
            logger.debug("服务端接收到请求：{}", msg);
            group.submit(() -> {
                Object response = requestHandler.handle(msg);
                if(ctx.channel().isActive() && ctx.channel().isWritable()) {
                    ctx.writeAndFlush(response);
                }else {
                    logger.error("通道不可写");
                }
            });
        }finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("处理过程调用时有错误发生：");
        cause.printStackTrace();
        ctx.close();
    }

}
